
package com.idealighter.game.bank.manager;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.idealighter.game.common.CommonMsgMgr;
import com.idealighter.game.constant.bank.InOutType;
import com.idealighter.game.core.assertions.HuohuaAssert;
import com.idealighter.game.core.assertions.IdeaAssert;
import com.idealighter.game.core.constant.Operator;
import com.idealighter.game.core.constant.PlayerType;
import com.idealighter.game.core.constant.SysConfigId;
import com.idealighter.game.core.error.ErrorCode;
import com.idealighter.game.core.util.PwdEncode;
import com.idealighter.game.dblog.service.DbLogService;
import com.idealighter.game.dictionary.dic.SysconfigDic;
import com.idealighter.game.dictionary.domain.SysconfigDomain;
import com.idealighter.game.log.core.LogReason;
import com.idealighter.game.log.struct.bank.DepositeWithdrawGoldLog;
import com.idealighter.game.message.core.ResMessage;
import com.idealighter.game.player.manager.PlayerMgr;
import com.idealighter.game.player.manager.PlayerMsgMgr;
import com.idealighter.game.player.service.bo.PlayerBo;
import com.idealighter.game.player.struct.Player;
import com.idealighter.game.server.db.datadb.TransferTotal;
import com.idealighter.game.server.db.datadb.dao.TransferGoldRecordDao;
import com.idealighter.game.server.db.datadb.generate.domain.TransferGoldRecordDomain;
import com.idealighter.utils.check.EmptyUtil;
import com.idealighter.utils.time.TimeUtil;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.mybatis.guice.transactional.Transactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 银行管理 .
 * 
 * @date 2015年11月11日 下午8:20:58
 *
 */
@Singleton
public class BankMgr {

  private static final Logger LOG = LoggerFactory.getLogger(BankMgr.class);

  // 转账手续费百分比
  public static final int DEFAULT_TRANSFER_HANDLING_CHARGE_PERCENTAGE = 20;

  // 奖励百分比
  public static final int DEFAULT_TRANSFER_REWARD_PERCENTAGE = 18;

  // 底数
  public static final int BASE_NUMBER = 1000;

  // 默认转账最低金币数
  public static final int DEFAULT_TRANSFER_MIN_GOLD = 100000;

  public static final int DEFAULT_TRANSFER_REWARD_MIN = 1000000;

  private static final int RECORD_LIMIT = 6;
  // SysconfigDic中的转账名单id
  // private static final int TRANSFER_LIST_ID = 106;

  @Inject
  private CommonMsgMgr commonMsgMgr;
  @Inject
  private SysconfigDic sysconfigDic;
  @Inject
  private PlayerMgr playerMgr;
  @Inject
  private PlayerMsgMgr playerMsgMgr;
  @Inject
  private BankMsgMgr bankMsgMgr;
  private TransferGoldRecordDao transferGoldRecordDao;

  @Inject
  public BankMgr(TransferGoldRecordDao transferGoldRecordDao) {
    this.transferGoldRecordDao = transferGoldRecordDao;
  }

  /**
   * 存金币 .
   * 
   * @param player 玩家.
   * @param gold .
   */
  public ResMessage depositeGold(Player player, long gold) {
    HuohuaAssert.isTrue(player.getGold() >= gold && gold > 0,
        ErrorCode.BANK_NOT_ENOUGH_GOLD_TOSAVE);

    final long beforeGold = player.getGold();
    final long beforeSafeGold = player.getSafeGold();
    playerMgr.addSafeGold(player, gold, LogReason.DEPOSITE_GOLD);
    playerMgr.minusGold(player, gold, LogReason.DEPOSITE_GOLD);



    DbLogService.log(new DepositeWithdrawGoldLog(player, 0, beforeGold, beforeSafeGold,
        player.getGold(), player.getSafeGold()));

    // 空返回
    return ResMessage.DEFAULT;
  }

  /**
   * 提取金币 .
   * 
   * @param player 玩家.
   * @param bankPwd .
   * @param gold .
   */
  public ResMessage withdrawGold(Player player, String bankPwd, long gold) {
    HuohuaAssert.isTrue(player.getBankPwd().equals(PwdEncode.encodeWithTail(bankPwd)),
        ErrorCode.BANK_PWD_ERROR);

    HuohuaAssert.isTrue(player.getSafeGold() >= gold && gold > 0,
        ErrorCode.BANK_NOT_ENOUGH_GOLD_WITHDRAW);

    final long beforeGold = player.getGold();
    final long beforeSafeGold = player.getSafeGold();

    playerMgr.addSafeGold(player, -gold, LogReason.WITHDRAW_GOLD);
    playerMgr.addGold(player, gold, LogReason.WITHDRAW_GOLD);

    DbLogService.log(new DepositeWithdrawGoldLog(player, 1, beforeGold, beforeSafeGold,
        player.getGold(), player.getSafeGold()));

    return ResMessage.DEFAULT;
  }

  /**
   * 转账 .
   * 
   * @param player 玩家.
   * @param bankPwd .
   * @param gold .
   * @param targetSuperId 目标靓号.
   */
  @Transactional
  public ResMessage transferGold(Player player, String bankPwd, long gold, long targetSuperId) {
    HuohuaAssert.isTrue(player.getSuperId() != targetSuperId, ErrorCode.INTERNAL_SERVER_ERROR);

    int transferMinGold = getTransferMinGold();
    HuohuaAssert.isTrue(gold >= transferMinGold, ErrorCode.BANK_TRANSFER_MIN);


    HuohuaAssert.isTrue(player.getBankPwd().equals(PwdEncode.encodeWithTail(bankPwd)),
        ErrorCode.BANK_PWD_ERROR);


    HuohuaAssert.isTrue(player.getSafeGold() >= gold, ErrorCode.BANK_NOT_ENOUGH_GOLD_TRANSFER);



    PlayerBo targetPlayerDom = playerMgr.selectPlayerBySuperId(targetSuperId);

    HuohuaAssert.isTrue(targetPlayerDom != null, ErrorCode.BANK_NOT_FIND_USER);



    long targetUserId = targetPlayerDom.getId();

    Player targetPlayer = playerMgr.getPlayer(targetUserId);

    if (targetPlayer != null) {
      targetPlayerDom = targetPlayer.playerBo();
    }

    byte fromType = player.getType();
    byte toType = targetPlayerDom.getType();
    int feeRate = 0;
    long fee = 0;
    long transferGold = gold;
    if (fromType == PlayerType.USER && toType == PlayerType.USER) {

      feeRate = getTransferHandlingChargePercent();
      transferGold = gold * (BASE_NUMBER - feeRate) / BASE_NUMBER;
      fee = gold - transferGold;
    } else if (fromType == PlayerType.USER && toType == PlayerType.AGENT) {
      // 1-31 修改 用户转 代理不收i
      transferGold = gold;
      feeRate = 0;
      fee = 0;
    } else if (fromType == PlayerType.AGENT && toType == PlayerType.AGENT) {
      transferGold = gold;
      feeRate = 0;
      fee = 0;
    } else if (fromType == PlayerType.AGENT && toType == PlayerType.USER) {

      feeRate = getTransferHandlingChargePercent();
      transferGold = gold * (BASE_NUMBER - feeRate) / BASE_NUMBER;
      fee = gold - transferGold;

      int rewardPercentage = getRewardChargePercent();

      long reward = gold * rewardPercentage / BASE_NUMBER;

      // 增加水果盒数量
      addTransferReward(player.getId(), reward);
    } else {
      LOG.error("用户[{}]({}) 装给用户 [{}]({}) 类型错误", player.getId(), fromType, targetPlayer.getId(),
          toType);
      IdeaAssert.isTrue(false, ErrorCode.INTERNAL_SERVER_ERROR);
    }


    Date now = TimeUtil.now();

    final long beforeSafeGold = player.getSafeGold();

    TransferGoldRecordDomain from = new TransferGoldRecordDomain();
    from.setOppositeType(targetPlayerDom.getType());
    from.setAfterSafeGold(beforeSafeGold - gold);
    from.setBeforeSafeGold(beforeSafeGold);
    from.setChangeSafeGold(-gold);
    from.setCreateTime(now);
    from.setFee(fee);
    from.setFeeRate(feeRate);
    from.setPlayerId(player.getId());
    from.setPlayerName(player.getPlayerName());
    from.setPlayerSuperId(player.getSuperId());
    from.setPlayerType(fromType);
    from.setOppositePlayerId(targetPlayerDom.getId());
    from.setOppositePlayerName(targetPlayerDom.getPlayerName());
    from.setOppositeSuperId(targetPlayerDom.getSuperId());
    from.setType(InOutType.OUT);

    int out = transferGoldRecordDao.insertSelective(from);

    IdeaAssert.isTrue(out > 0, ErrorCode.INTERNAL_SERVER_ERROR);

    final long beforeTargetSafeGold = targetPlayerDom.getSafeGold().get();

    TransferGoldRecordDomain to = new TransferGoldRecordDomain();
    to.setOppositeType(player.getType());
    to.setAfterSafeGold(beforeTargetSafeGold + transferGold);
    to.setBeforeSafeGold(beforeTargetSafeGold);
    to.setChangeSafeGold(transferGold);
    to.setCreateTime(now);
    to.setFee(fee);
    to.setFeeRate(feeRate);
    to.setPlayerId(targetPlayerDom.getId());
    to.setPlayerName(targetPlayerDom.getPlayerName());
    to.setPlayerSuperId(targetPlayerDom.getSuperId());
    to.setPlayerType(toType);
    to.setOppositePlayerId(player.getId());
    to.setOppositePlayerName(player.getPlayerName());
    to.setOppositeSuperId(player.getSuperId());
    to.setType(InOutType.IN);

    out = transferGoldRecordDao.insertSelective(to);

    IdeaAssert.isTrue(out > 0, ErrorCode.INTERNAL_SERVER_ERROR);

    playerMgr.addSafeGold(player, -gold, LogReason.TRANSFER_GOLD);

    if (targetPlayer != null) {
      playerMgr.addSafeGold(targetPlayer, transferGold, LogReason.TRANSFER_GOLD);
    } else {
      playerMgr.addSafeGold(targetPlayerDom, transferGold, LogReason.TRANSFER_GOLD);
    }
    // 手动同步一次
    // 同步自己
    playerMgr.updatePlayer(player.playerBo());

    // 同步目标用户
    playerMgr.updatePlayer(targetPlayerDom);

    // 用户通知

    /*
     * 在线发送提示转账消息框 .
     */
    if (targetPlayer != null) {
      commonMsgMgr.sendTipDlgMsg(targetPlayer, ErrorCode.BANK_TRANSFER_MSG, Operator.SYSTEM,
          player.getPlayerName(), "" + transferGold);
    }

    // 发送转账成功消息(客户端有逻辑处理)
    return bankMsgMgr.sendTransferGoldSuccessMsg(from);

    // DbLogService
    // .log(new TransferGoldLog(player, targetPlayer.getSuperId(), targetPlayer.getPlayerName(),
    // feeRate, fee, beforeGold, beforeSafeGold, player.getGold(), player.getSafeGold()));
    //
    // DbLogService.log(new TransferGoldLog(player, targetUserId, beforeGold, beforeSafeGold,
    // player.getGold(), player.getSafeGold()));
  }

  /**
   * 最小转账金额 .
   * 
   * @return .
   */
  private int getTransferMinGold() {
    SysconfigDomain cfgDom = sysconfigDic.get(SysConfigId.BANK_TRANSFER_MIN_GOLD);

    return cfgDom == null ? DEFAULT_TRANSFER_MIN_GOLD : Integer.parseInt(cfgDom.getVal());
  }

  private long getTranferRewardMin() {
    SysconfigDomain sysconfigDomain = sysconfigDic.get(SysConfigId.BANK_TRANSFER_REWARD_MIN);

    return sysconfigDomain == null ? DEFAULT_TRANSFER_REWARD_MIN
        : Long.parseLong(sysconfigDomain.getVal());
  }

  /**
   * 获取转账手续费 .
   * 
   * @return .
   */
  private int getTransferHandlingChargePercent() {
    SysconfigDomain cfgDom = sysconfigDic.get(SysConfigId.BANK_TRANSFER_FEE_PERCENTAGE);

    return cfgDom == null ? DEFAULT_TRANSFER_HANDLING_CHARGE_PERCENTAGE
        : Integer.parseInt(cfgDom.getVal());
  }

  private int getRewardChargePercent() {
    SysconfigDomain cfgDom = sysconfigDic.get(SysConfigId.BANK_TRANSFER_REWARD_PERCENTAGE);

    return cfgDom == null ? DEFAULT_TRANSFER_REWARD_PERCENTAGE
        : Integer.parseInt(cfgDom.getVal());
  }



  /**
   * 添加礼物盒奖励.
   * 
   * @param playerId 玩家id.
   * @param transferReward 礼物盒奖励.
   */
  public void addTransferReward(long playerId, long transferReward) {
    if (transferReward == 0) {
      LOG.warn("玩家[{}]增加的礼物盒金币不能为0", playerId);
      return;
    }

    PlayerBo playerDom = playerMgr.selectPlayer(playerId);

    long beforeTransferReward = playerDom.getTransferReward();
    long afterTransferReward = beforeTransferReward + transferReward;

    playerDom.setTransferReward(afterTransferReward);

    Player player = playerMgr.getPlayer(playerId);
    if (player != null) {
      playerMsgMgr.noticeAttrChangeMsg(player, 10, afterTransferReward);
    }
  }

  /**
   * 玩家转账列表.
   * 
   * @param player 玩家.
   * @param recordId 最后的id.
   * @param next 是否下一页.
   * @param oppositeType 对方类型.
   */
  public ResMessage transferGoldList(Player player, Integer recordId, boolean next,
      Byte oppositeType) {
    List<TransferGoldRecordDomain> transferLogs = null;

    if (next) {
      transferLogs = transferGoldRecordDao.selectNextByPage(player.getId(), recordId,
          oppositeType, RECORD_LIMIT);
    } else {
      transferLogs = transferGoldRecordDao.selectPreByPage(player.getId(), recordId, oppositeType,
          RECORD_LIMIT);
      if (EmptyUtil.listIsNotEmpty(transferLogs)) {
        Collections.reverse(transferLogs);
      }
    }

    Integer lastId = null;
    boolean hasNext = false;
    if (EmptyUtil.listIsNotEmpty(transferLogs)) {
      lastId = transferLogs.get(transferLogs.size() - 1).getId();
      hasNext = transferGoldRecordDao.countNextTotal(player.getId(), lastId, oppositeType) > 0;
    }

    long total = transferGoldRecordDao.countTotalSum(player.getId(), oppositeType);


    return bankMsgMgr.sendTransferRecordsMsg(transferLogs, total, hasNext);
  }

  /**
   * 获取礼物盒奖励.
   * 
   * @param player 玩家.
   */
  public ResMessage getTranferReward(Player player) {
    long min = getTranferRewardMin();
    long transferReward = player.getTransferReward();
    HuohuaAssert.isTrue(transferReward >= min, ErrorCode.BANK_TRANSFER_REWARD_NOT_ENOUGH);
    // if (transferReward < min) {
    // commonMsgMgr.sendErrorDlgMsg(player, ErrorCode.BANK_TRANSFER_REWARD_NOT_ENOUGH,
    // Operator.SYSTEM);
    // return;
    // }
    long getGold = transferReward - transferReward % min;
    playerMgr.addSafeGold(player, getGold, LogReason.TRANSFER_GET_REWARD);
    addTransferReward(player.getId(), -getGold);

    return ResMessage.DEFAULT;
  }

  /**
   * 获取转账金币统计.
   * 
   * @param player 玩家.
   */
  public ResMessage transferCount(Player player) {
    long inFromAgent = 0;
    long inFromUser = 0;
    long outToAgent = 0;
    long outToUser = 0;
    Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.HOUR_OF_DAY, 0);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    calendar.set(Calendar.MILLISECOND, 0);
    Date beginTime = calendar.getTime();

    calendar.add(Calendar.DATE, 1);

    Date entTime = calendar.getTime();

    List<TransferTotal> transferTotals =
        transferGoldRecordDao.sumTotal(player.getId(), beginTime, entTime);
    if (EmptyUtil.listIsNotEmpty(transferTotals)) {
      for (TransferTotal transferTotal : transferTotals) {
        if (transferTotal.getType() == InOutType.IN) {
          if (transferTotal.getOppositeType() == PlayerType.USER) {
            inFromUser = transferTotal.getTotal();
          } else if (transferTotal.getOppositeType() == PlayerType.AGENT) {
            inFromAgent = transferTotal.getTotal();
          }
        } else if (transferTotal.getType() == InOutType.OUT) {
          if (transferTotal.getOppositeType() == PlayerType.USER) {
            outToUser = transferTotal.getTotal();
          } else if (transferTotal.getOppositeType() == PlayerType.AGENT) {
            outToAgent = transferTotal.getTotal();
          }
        }
      }
    }
    return bankMsgMgr.sendTransferCountMsg(outToAgent, outToUser, inFromAgent, inFromUser);
  }

}
